package com.sinoeyes.common.result;

import com.sinoeyes.common.constant.RConstant;
import lombok.*;
import org.apache.commons.lang3.StringUtils;

import java.util.HashMap;


/**
 * 统一API响应结果封装
 * R
 *
 * @author aries.hao
 */
@Getter
@Setter
@ToString
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class R<T> extends HashMap<String, Object> {

    private static final long serialVersionUID = 1L;

    private String codeKey = RConstant.DEFAULT_RESULT_CODE_KEY;

    private String messageKey = RConstant.DEFAULT_RESULT_MESSAGE_KEY;

    private String dataKey = RConstant.DEFAULT_RESULT_DATA_KEY;

    private String pageKey = RConstant.DEFAULT_RESULT_PAGE_KEY;

    private String successKey = RConstant.DEFAULT_RESULT_SUCCESS_KEY;

    private static String SUCCESS_CODE = RCode.SUCCESS.getCode();

    private static String FAILURE_CODE = RCode.FAILURE.getCode();


    private R(RCode rCode) {
        this(rCode.getCode(), rCode.getMessage());
    }

    private R(RCode rCode, String msg) {
        this(rCode.getCode(), msg);
    }

    private R(RCode rCode, T data) {
        this(rCode, data, rCode.getMessage());
    }

    private R(RCode rCode, T data, String msg) {
        this(rCode.getCode(), data, msg);
    }


    private R(String code, String message) {
        this.put(codeKey, code);
        this.put(messageKey, message);
        appendSuccess(code);
    }

    private R(String code, T data, String message) {
        this.put(codeKey, code);
        this.put(messageKey, message);
        this.put(dataKey, data);
        appendSuccess(code);
    }

    private R(String code, P<T> page, String message) {
        this.put(codeKey, code);
        this.put(messageKey, message);
        this.put(dataKey, page.getData());
        this.put(pageKey, page.getPage());
        appendSuccess(code);
    }

    /**
     * 返回R
     *
     * @param code 状态码
     * @param data 数据
     * @param msg  消息
     * @param <T>  T 泛型标记
     * @return R
     */
    public static <T> R<T> success(String code, T data, String msg) {
        return new R<>(code, data, msg == null ? RConstant.DEFAULT_NULL_MESSAGE : msg);
    }

    /**
     * 返回R
     *
     * @param data 数据
     * @param msg  消息
     * @param <T>  T 泛型标记
     * @return R
     */
    public static <T> R<T> success(T data, String msg) {
        return success(SUCCESS_CODE, data, msg);
    }

    public static <T> R<T> success(P<T> page, String msg) {
        return new R<T>(SUCCESS_CODE, page, msg);
    }

    /**
     * 返回R
     *
     * @param data  数据
     * @param rCode rcode
     * @param <T>   T 泛型标记
     * @return R
     */
    public static <T> R<T> success(T data, RCode rCode) {
        return success(rCode.getCode(), data, rCode.getMessage());
    }

    /**
     * 返回R
     *
     * @param data 数据
     * @param <T>  T 泛型标记
     * @return R
     */
    public static <T> R<T> success(T data) {
        return success(data, RConstant.DEFAULT_SUCCESS_MESSAGE);
    }

    public static <T> R<T> success() {
        return success(RConstant.DEFAULT_SUCCESS_MESSAGE);
    }

    public static <T> R<T> success(P<T> page) {
        return success(page, RConstant.DEFAULT_SUCCESS_MESSAGE);
    }

    /**
     * 返回R
     *
     * @param msg 消息
     * @param <T> T 泛型标记
     * @return R
     */
    public static <T> R<T> success(String msg) {
        return new R<>(SUCCESS_CODE, msg);
    }

    /**
     * 返回R
     *
     * @param rCode 业务代码
     * @param <T>   T 泛型标记
     * @return R
     */
    public static <T> R<T> success(RCode rCode) {
        return new R<>(rCode);
    }

    /**
     * 返回R
     *
     * @param rCode 业务代码
     * @param msg   消息
     * @param <T>   T 泛型标记
     * @return R
     */
    public static <T> R<T> success(RCode rCode, String msg) {
        return new R<>(rCode, msg);
    }

    /**
     * 返回R
     *
     * @param msg 消息
     * @param <T> T 泛型标记
     * @return R
     */
    public static <T> R<T> failure(String msg) {
        return new R<>(FAILURE_CODE, msg);
    }

    public static <T> R<T> failure() {
        return new R<>(FAILURE_CODE, RConstant.DEFAULT_FAILURE_MESSAGE);
    }


    /**
     * 返回R
     *
     * @param code 状态码
     * @param msg  消息
     * @param <T>  T 泛型标记
     * @return R
     */
    public static <T> R<T> failure(String code, String msg) {
        return new R<>(code, msg);
    }

    public static <T> R<T> failureNull() {
        return new R<>(FAILURE_CODE, RConstant.DEFAULT_NULL_MESSAGE);
    }

    /**
     * 返回R
     *
     * @param rCode 业务代码
     * @param <T>   T 泛型标记
     * @return R
     */
    public static <T> R<T> failure(RCode rCode) {
        return new R<>(rCode);
    }

    /**
     * 返回R
     *
     * @param rCode 业务代码
     * @param msg   消息
     * @param <T>   T 泛型标记
     * @return R
     */
    public static <T> R<T> failure(RCode rCode, String msg) {
        return new R<>(rCode, msg);
    }

    /**
     * 空
     *
     * @return
     */
    public static <T> R<T> none() {
        return new R<>();
    }


    /**
     * 除正常返回的json内容内的标准字段外，额外添加自定义返回字段使用
     *
     * @param key   属性名
     * @param value 属性值
     * @return R
     */
    public R<T> fill(String key, Object value) {
        this.put(key, value);
        return this;
    }

    /**
     * 自定义替换返回json key命名（改变结果集内map的key命名）
     *
     * @param codeKey
     * @param messageKey
     * @param dataKey
     * @param successKey
     */
    public void setCodeKeys(String codeKey, String messageKey, String dataKey, String successKey) {
        if (StringUtils.isNotBlank(codeKey)) {
            this.codeKey = codeKey;
        }
        if (StringUtils.isNotBlank(messageKey)) {
            this.messageKey = messageKey;
        }
        if (StringUtils.isNotBlank(dataKey)) {
            this.dataKey = dataKey;
        }
        if (StringUtils.isNotBlank(successKey)) {
            this.successKey = successKey;
        }
    }

    public static void changeCodekey(String codeKey, String messageKey, String dataKey, String successKey){
        new R().setCodeKeys(codeKey, messageKey, dataKey, successKey);
    }

    private void appendSuccess(String code) {
        if (SUCCESS_CODE.equals(code)) {
            fill(successKey, true);
        } else {
            fill(successKey, false);
        }
    }
}

